﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using HYCodeBase.Math;
using HYRevitCode.TransformUtility;

namespace HYRevitCode.FaceCalculateUtility
{
	internal class GeometryHelper
	{
		internal static double GetTowPlanarFaceDis(PlanarFace Face1, PlanarFace Face2)
		{
			Face face = MathUtility.Lessthan_Or_Equal(Face1.Area, Face2.Area) ? Face1 : Face2;
			PlanarFace useFace = MathUtility.Lessthan_Or_Equal(Face1.Area, Face2.Area) ? Face2 : Face1;
			double num = -1.0;
			foreach (CurveLoop curveLoop in face.GetEdgesAsCurveLoops())
			{
				foreach (Curve curve in curveLoop)
				{
					foreach (XYZ usePoint in new List<XYZ>
					{
						curve.GetEndPoint(0),
						curve.GetEndPoint(1)
					})
					{
						num = GeometryHelper.DisPointToPlanarFace(usePoint, useFace);
						if (num != -1.0)
						{
							return num;
						}
					}
				}
			}
			return num;
		}

		internal static double DisPointToPlanarFace(XYZ usePoint, PlanarFace useFace)
		{
			double num = -1.0;
			Curve curve = Line.CreateUnbound(usePoint, useFace.FaceNormal);
			IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
			useFace.Intersect(curve, out intersectionResultArray);
			double result;
			try
			{
				foreach (object obj in intersectionResultArray)
				{
					IntersectionResult intersectionResult = (IntersectionResult)obj;
					if (intersectionResult.XYZPoint != null)
					{
						num = intersectionResult.XYZPoint.DistanceTo(usePoint);
						return num;
					}
				}
				result = num;
			}
			catch (Exception)
			{
				result = -1.0;
			}
			return result;
		}

		internal static List<XYZ> GetBoundaryPoint(PlanarFace useFace)
		{
			List<XYZ> list = new List<XYZ>();
			foreach (Curve curve in useFace.GetEdgesAsCurveLoops().ToList<CurveLoop>().First<CurveLoop>())
			{
				list.Add(curve.GetEndPoint(0));
				list.Add(curve.GetEndPoint(1));
			}
			return list;
		}

		internal static void GetBuildingCutPoint(XYZ buildingMax, XYZ buildingMin, int nXNumbe, int nYNumbe, int nZNumbe, out List<List<XYZ>> lstLstAllPoint, out List<double> lstUseHeight)
		{
			lstLstAllPoint = null;
			lstUseHeight = null;
			List<XYZ> boxBottemPoints = SplitBoxPacker.GetBoxBottemPoints(buildingMax, buildingMin);
			if (boxBottemPoints != null)
			{
				double num = boxBottemPoints[0].DistanceTo(boxBottemPoints[1]) / (double)nXNumbe;
				double num2 = boxBottemPoints[1].DistanceTo(boxBottemPoints[2]) / (double)nYNumbe;
				double num3 = (buildingMax.Z - buildingMin.Z) / (double)nZNumbe;
				lstLstAllPoint = new List<List<XYZ>>();
				Transform useTransform = Transform.CreateTranslation(new XYZ(num, 0.0, 0.0));
				List<XYZ> listFromPoint = GeometryHelper.GetListFromPoint(boxBottemPoints[0], nXNumbe - 1, useTransform);
				listFromPoint.Add(boxBottemPoints[1]);
				lstLstAllPoint.Add(listFromPoint);
				for (int i = 1; i < nYNumbe; i++)
				{
					List<XYZ> list = new List<XYZ>();
					for (int j = 0; j < lstLstAllPoint.Last<List<XYZ>>().Count; j++)
					{
						Transform transform = Transform.CreateTranslation(new XYZ(0.0, num2, 0.0));
						XYZ item = TransformUtilityMethod.TransformPoint(lstLstAllPoint.Last<List<XYZ>>()[j], transform);
						list.Add(item);
					}
					lstLstAllPoint.Add(list);
				}
				List<XYZ> listFromPoint2 = GeometryHelper.GetListFromPoint(boxBottemPoints[3], nXNumbe - 1, useTransform);
				listFromPoint2.Add(boxBottemPoints[2]);
				lstLstAllPoint.Add(listFromPoint2);
				lstUseHeight = new List<double>();
				lstUseHeight.Add(boxBottemPoints[0].Z);
				for (int k = 1; k < nZNumbe; k++)
				{
					lstUseHeight.Add(lstUseHeight.Last<double>() + num3);
				}
				lstUseHeight.Add(buildingMax.Z);
			}
		}

		internal static void GetBulidingMaxAndMin(List<Element> lstElement, out XYZ buildingMax, out XYZ buildingMin)
		{
			buildingMax = null;
			buildingMin = null;
			List<XYZ> list = new List<XYZ>();
			foreach (Element element in lstElement)
			{
				BoundingBoxXYZ boundingBoxXYZ = element.get_BoundingBox(null);
				if (boundingBoxXYZ != null)
				{
					list.Add(boundingBoxXYZ.Max);
					list.Add(boundingBoxXYZ.Min);
				}
			}
			GeometryHelper.GetMaxAndMinFromAllPoints(ref buildingMax, ref buildingMin, list);
		}

		private static void GetMaxAndMinFromAllPoints(ref XYZ buildingMax, ref XYZ buildingMin, List<XYZ> lstAllBoxPoint)
		{
			if (lstAllBoxPoint.Count > 0)
			{
				List<XYZ> source = (from p in lstAllBoxPoint
				orderby p.X
				select p).ToList<XYZ>();
				List<XYZ> source2 = (from p in lstAllBoxPoint
				orderby p.Y
				select p).ToList<XYZ>();
				List<XYZ> source3 = (from p in lstAllBoxPoint
				orderby p.Z
				select p).ToList<XYZ>();
				buildingMin = new XYZ(source.First<XYZ>().X, source2.First<XYZ>().Y, source3.First<XYZ>().Z);
				buildingMax = new XYZ(source.Last<XYZ>().X, source2.Last<XYZ>().Y, source3.Last<XYZ>().Z);
			}
		}

		internal static void GetBulidingMaxAndMin(List<Solid> lstSolid, out XYZ buildingMax, out XYZ buildingMin)
		{
			buildingMax = null;
			buildingMin = null;
			List<XYZ> list = new List<XYZ>();
			foreach (Solid solid in lstSolid)
			{
				foreach (PlanarFace useFace in GeometryHelper.GetSolidPlanarFace(solid))
				{
					list.AddRange(GeometryHelper.GetBoundaryPoint(useFace));
				}
			}
			GeometryHelper.GetMaxAndMinFromAllPoints(ref buildingMax, ref buildingMin, list);
		}

		public static List<PlanarFace> GetSolidPlanarFace(Solid solid)
		{
			List<PlanarFace> list = new List<PlanarFace>();
			foreach (object obj in solid.Faces)
			{
				Face face = (Face)obj;
				if (face is PlanarFace)
				{
					list.Add(face as PlanarFace);
				}
			}
			return list;
		}

		internal static List<XYZ> GetListFromPoint(XYZ originalPoint, int nTransNumber, Transform useTransform)
		{
			List<XYZ> list = new List<XYZ>();
			list.Add(originalPoint);
			for (int i = 0; i < nTransNumber; i++)
			{
				XYZ item = TransformUtilityMethod.TransformPoint(list.Last<XYZ>(), useTransform);
				list.Add(item);
			}
			return list;
		}
	}
}
